//
//  YSMethodForwardViewController.m
//  YSKitDemo
//
//  Created by Kyson on 2018/9/4.
//  Copyright © 2018年 YangShen. All rights reserved.
//

#import "YSMethodForwardViewController.h"
#import <objc/runtime.h>

@interface RuntimeMethodHelper: NSObject

@end
@implementation RuntimeMethodHelper

- (void)hello {
    NSLog(@"%@, %p", self, _cmd);
}

@end

#pragma mark - HiClass
@interface HiClass: NSObject
{
    RuntimeMethodHelper *_helper;
}

- (void)hello;
+ (HiClass *)hi;
@end

@implementation HiClass

- (instancetype)init {
    if (self = [super init]) {
        _helper = [[RuntimeMethodHelper alloc] init];
    }
    return self;
}

void functionForMethod(id self, SEL _cmd) {
    NSLog(@"hello!");
}

Class functionForClassMethod(id self, SEL _cmd) {
    NSLog(@"Hi!");
    return [HiClass class];
}

#pragma mark - 1. 动态方法解析
// selector : 那个未知的选择子
// 返回YES则结束消息转发
// 返回NO则进入备用接受者
+ (BOOL)resolveClassMethod:(SEL)sel {
    NSLog(@"resolveClassMethod");
    NSString *selString = NSStringFromSelector(sel);
    if ([selString isEqualToString:@"hi"]) {
        Class metaClass = objc_getMetaClass("HiClass");
        class_addMethod(metaClass, @selector(hi), (IMP)functionForClassMethod, "v@:");
        return YES;
    }
    return [super resolveClassMethod:sel];
}

/**
+ (BOOL)resolveInstanceMethod:(SEL)sel {
    NSLog(@"resolveInstanceMethod");
    NSString *selString = NSStringFromSelector(sel);
    if ([selString isEqualToString:@"hello"]) {
        class_addMethod(self, @selector(hello), (IMP)functionForMethod, "v@:");
        return YES;
    }
    return [super resolveInstanceMethod:sel];
}
 */

#pragma mark - 2. 备用接受者
/**
// selector : 那个未知的消息
// 返回一个能响应该未知选择子的备用对象
- (id)forwardingTargetForSelector:(SEL)aSelector {
    NSLog(@"forwardingTargetForSelector");
    NSString *selectorString = NSStringFromSelector(aSelector);
    // 将消息交给_helper来处理
    if ([selectorString isEqualToString:@"hello"]) {
        return _helper;
    }
    return [super forwardingTargetForSelector:aSelector];
}
*/

#pragma mark - 3、完整消息转发
// invocation : 封装了与那条尚未处理的消息相关的所有细节的对象
- (void)forwardInvocation:(NSInvocation *)anInvocation {
    NSLog(@"forwardInvocation");
    if ([RuntimeMethodHelper instancesRespondToSelector:anInvocation.selector]) {
        [anInvocation invokeWithTarget:_helper];
    }
}

// 必须重新这个方法，消息转发机制使用从这个方法中获取的信息来创建NSInvocation对象
// NSMethodSignature : 该selector对应的方法签名
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector {
    NSLog(@"methodSignatureForSelector");
    NSMethodSignature *signature = [super methodSignatureForSelector:aSelector];
    if (!signature) {
        if ([RuntimeMethodHelper instancesRespondToSelector:aSelector]) {
            signature = [RuntimeMethodHelper instanceMethodSignatureForSelector:aSelector];
        }
    }
    return signature;
}

@end



@interface YSMethodForwardViewController ()

@end

@implementation YSMethodForwardViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    self.navigationItem.title = @"消息转发";
    
    [self testMehtodForward];
}

- (void)testMehtodForward {
    NSLog(@"----------------------");
    NSLog(@"测试消息转发");
    NSLog(@"----------------------");
    
    HiClass *hiCls = [[HiClass alloc] init];
    [hiCls hello];
    [HiClass hi];
    
    NSLog(@"\n");
}

@end
